package migrations

import (
	"errors"
	"fmt"

	"go.uber.org/zap"

	"gorm.io/gorm"
)

type MigrationStage struct {
	Name     string
	Function func(db *gorm.DB, name string) error
}

// Migrate ...
func Migrate(db *gorm.DB, migrations []MigrationStage) error {
	for _, m := range migrations {
		/*
			if MigrationExists(db, m.Name) {
				continue
			}
		*/
		if err := m.Function(db, m.Name); err != nil {
			return err
		}

		if err := SaveMigration(db, m.Name); err != nil {
			return err
		}
	}

	return nil
}

// MigrateAll runs bootstrap, then all migration functions listed against
// the specified database and logs any errors
func MigrateAll(db *gorm.DB, migrationFunctions []func(*gorm.DB) error) {
	logger, _ := zap.NewProduction()
	defer logger.Sync() // flushes buffer, if any
	sugar := logger.Sugar()

	if err := Bootstrap(db); err != nil {
		sugar.Errorf(err.Error())
	}

	for _, m := range migrationFunctions {
		if err := m(db); err != nil {
			sugar.Errorf(err.Error())
		}
	}
}

//MigrationExists check if the migration called migrationName has been run already
func MigrationExists(db *gorm.DB, migrationName string) bool {
	migration := new(Migration)
	result := db.Where("name = ?", migrationName).First(migration)

	logger, _ := zap.NewProduction()
	defer logger.Sync() // flushes buffer, if any
	sugar := logger.Sugar()

	unFound := errors.Is(result.Error, gorm.ErrRecordNotFound)

	// 检查 ErrRecordNotFound 错误
	if unFound {
		// not found
		sugar.Infof("Running %s migration", migrationName)
	} else {
		// found
		sugar.Infof("Skipping %s migration", migrationName)
	}

	return unFound
}

// SaveMigration saves a migration to the migration table
func SaveMigration(db *gorm.DB, migrationName string) error {
	migration := new(Migration)
	migration.Name = migrationName

	result := db.Create(migration)
	logger, _ := zap.NewProduction()
	defer logger.Sync() // flushes buffer, if any
	sugar := logger.Sugar()
	if result.Error != nil {
		sugar.Errorf("Error saving record to migrations table: %s", error.Error)
		return fmt.Errorf("Error saving record to migrations table: %s", error.Error)
	}
	return nil
}
